home *** CD-ROM | disk | FTP | other *** search
- /*
- DPMI.C -- DPMI functions, plus some undocumented Windows functions that
- provide the same functionality, plus several layers of "sugar-coating"
- on top of these low-level services, to make them palatable
-
- Copyright (c) Ziff Communications, Co.
- PC Magazine * Andrew Schulman
- */
-
- #include <Windows.h>
- #include <dos.h>
- #include "dpmi.h"
-
- /* are we already in protected mode, running under DPMI? */
- BOOL dpmi_present()
- {
- asm {
- mov ax, 0x1686;
- int 0x2F;
- not ax;
- }
- return (_AX);
- }
-
- /* get DPMI kernal version, flags and (?)process number */
- void dpmi_version(unsigned *pmaj, unsigned *pmin,
- unsigned *pflags, unsigned *pproc)
- {
- unsigned char maj, min, proc;
- unsigned flags;
- asm {
- mov ax, 0x0400;
- int 0x31;
- mov maj, ah;
- mov min, al;
- mov flags, bx;
- mov proc, cl
- }
- *pmaj = maj;
- *pmin = min;
- *pflags = flags;
- *pproc = proc;
- }
-
- /* Perform a real-mode interrupt from protected mode */
- BOOL dpmi_rmode_intr(unsigned intno, unsigned flags,
- unsigned copywords, RMODE_CALL far *rmode_call)
- {
- unsigned success;
-
- if (flags) intno |= 0x0100;
- asm {
- push es;
- push di;
- mov ax, 0x0300; // simulate real-mode interrupt
- mov bx, word ptr intno; // interrupt number, flags
- mov cx, word ptr copywords; // words to copy from pmode to rmode stack
- les di, dword ptr rmode_call; // ES:DI = addr of rmode call struct
- int 0x31; // call DPMI
- pop di;
- pop es;
- jnc short done; // return TRUE
- mov success, 0; // return FALSE
- }
- done:
- return (success);
- }
-
- /* Allocates a single protected-mode LDT selector */
- unsigned dpmi_sel(void)
- {
- unsigned rc=0;
-
- asm {
- xor ax, ax; // Allocate LDT descriptor
- mov cx, 1; // allocate just one
- int 0x31; // call DPMI
- jc short done;
- mov rc, ax;
- }
- done:
- return (rc);
- }
-
- /* set a descriptor for a protected mode selector */
- BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
- {
- int success=1; // TRUE
-
- asm {
- push es;
- push di;
- mov ax, 0x000c // set descriptor
- mov bx, word ptr pmodesel; // protected mode selector
- les di, dword ptr d; // descriptor
- int 0x31 // call DPMI
- pop di;
- pop es;
- jnc short done;
- mov success, 0; // return TRUE
- jmp short done
- }
- done:
- return (success);
- }
-
- /* get the associated descriptor for a protected mode selector */
- /*** same as set_desc, except for mov ax, 0x000b .vs. 0x000c ***/
- BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
- {
- int success=1;
- asm {
- push es;
- push di;
- mov ax, 0x000b // get descriptor
- mov bx, word ptr pmodesel; // protected mode selector
- les di, dword ptr d; // descriptor
- int 0x31 // call DPMI
- pop di;
- pop es;
- jnc short done;
- mov success, 0; // return FALSE
- }
- done:
- return (success);
- }
-
- /* free a selector */
- BOOL dpmi_sel_free(unsigned pmodesel)
- {
- int success=1;
- asm {
- mov ax, 0x0001; // free LDT descriptor
- mov bx, word ptr pmodesel; // protected mode selector
- int 0x31; // call DPMI
- jnc short done;
- mov success, 0; // return FALSE
- }
- done:
- return (success);
- }
-
- /* layer on top of DPMI and Windows services *******************************/
-
- /* allocate a segment of real DOS memory, and return both real and prot segs */
- unsigned DOSAllocRealSeg(DWORD bytes, unsigned *ppara, unsigned *psel)
- {
- DWORD dw = GlobalDosAlloc(bytes);
- if (dw == NULL)
- return 8; // insufficient memory
- *ppara = HIWORD(dw);
- *psel = LOWORD(dw);
- return 0;
- }
-
- /* free DOS segment */
- unsigned DOSFreeRealSeg(unsigned sel)
- {
- return(GlobalDosFree(sel) != NULL);
- }
-
- /*
- Use DPMI services to map a real-mode paragraph into protected mode
- address space. First we get a selector using the DPMI "Allocate
- LDT Descriptors" call (INT 31h, Function 0000h), via our dpmi_sel()
- function. We then get the descriptor for any old data segment in
- our program so that it can be used as a template of sorts for the
- new descriptor. This is done with the DPMI "Get Descriptor" call
- (INT 31h, Function 000Bh), via our dpmi_get_descriptor() function.
- We then alter the descriptor to reflect the "rmpara" and "size"
- requested, and finally associate the descriptor with our LDT
- selector, using the DPMI "Set Descriptor" call (INT 31h, Function
- 000Ch). All the user needs, of course, is the selector itself.
- */
- unsigned DOSMapRealSeg(unsigned rmpara, DWORD size, unsigned far *psel)
- {
- DESCRIPTOR d;
- unsigned long addr;
- unsigned sel = dpmi_sel();
- if (! sel)
- return 8; // insufficient memory
- /* make sure psel is valid */
- //if (! verw(FP_SEG(psel)))
- // return 490; // invalid selector error
- /* get descriptor for any data segment */
- dpmi_get_descriptor(FP_SEG(psel), &d);
- d.limit = (unsigned) size - 1;
- addr = ((unsigned long) rmpara) << 4L;
- d.addr_lo = (unsigned) addr;
- d.addr_hi = (unsigned char) (addr >> 16);
- d.reserved = d.addr_xhi = 0;
- dpmi_set_descriptor(sel, &d);
- *psel = sel;
- return 0; // success
- }
-
- /* free a protected mode selector */
- unsigned DOSFreeSeg(unsigned sel)
- {
- return ! dpmi_sel_free(sel);
- }
-
- /*
- Use undocumented Windows function to retrieve the real-mode equivalent
- to a protected mode pointer. Of course, we could also have used
- dpmi_get_descriptor() here, but GetSelectorBase() is slightly more
- convenient. If the base of the selector is above the one-megabyte
- watershed, then there is no real-mode equivalent, so we return NULL.
- */
- void far *DOSProtToReal(void far *prot)
- {
- unsigned long base = GetSelectorBase(FP_SEG(prot));
- if (base > 0xFFFFFL)
- return NULL; /* not accessible in real mode */
- else
- return MAKEP(base >> 4, (base & 0x0F) + FP_OFF(prot));
- }
-
- unsigned __0000H = 0; /* undocumented Windows selector */
- unsigned mapped = 0; /* keep track of mapped selectors */
-
- unsigned get_mapped(void)
- {
- return mapped;
- }
-
- /*
- Map a real-mode pointer into our protected mode address space.
- If the real-mode pointer is in the first 64K of memory, use the
- undocumented Windows selector __0000H. Otherwise, use DPMI services
- via our DOSMapRealSeg() function, which provides a more convenient
- layer on top of DPMI. This map_real() function in turn provides a more
- convenient layer on top of DOSMapRealSeg(). Note that DOSMapRealSeg()
- takes a full segment:offset real-mode pointer.
- */
- void far *map_real(void far *rptr, unsigned long size)
- {
- unsigned seg, ofs, sel;
-
- if (! __0000H) /* one time init: get undocumented Windows selector */
- __0000H = LOWORD(GetProcAddress(GetModuleHandle("KERNAL"),"__0000H"));
-
- seg = FP_SEG(rptr);
- ofs = FP_OFF(rptr);
- if ((seg < 0x1000) && ((ofs + size) < 0xFFFF))
- return MAKEP(__0000H, (seg << 4) + ofs);
- if (DOSMapRealSeg(seg, size + ofs, &sel) != 0)
- return 0;
- mapped++;
- return MAKEP(sel, ofs);
- }
-
- void free_mapped_seg(void far *fp)
- {
- unsigned sel = FP_SEG(fp);
- if (sel == __0000H)
- return;
- if (DOSFreeSeg(sel) == 0)
- mapped--;
- }
-
- #ifdef ENABLE_286
- /* use Intel VERW instruction to validate pointers */
- unsigned verw(unsigned sel)
- {
- asm {
- mov ax, 1;
- verw sel;
- je short ok;
- xor ax, ax;
- }
- ok:
- return (_AX);
- }
- #endif
-